#include <iostream>
#include <cstdlib>
#include <ctime>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <sstream>

using namespace std;

//Global Variables
const int GRIDX = 22, GRIDY = 22, SHOTS = 10;
bool win = false;

//Function Declarations

//takes the current grid and paints it too the screen.
//All ships (held as 'a' in the grid) are hidden.
//should NOT alter values in the grid
void paintGrid(char grid[][GRIDY]);

//takes X and Y coordinates for the targeted shot and the grid
//the grid is is updated with a hit or miss marker at the given coordinate
//returns a 0 for a miss and a 1 for a hit
int shot(int x, int y, char grid[][GRIDY]);

//takes a grid and and fills it with blank / default values
// also adds ships randomly, assigned 'a' values to the grid locations
void fillGrid(char grid[][GRIDY]);

//takes the grid and performs a full search for any remaining ships
//returns true if no ships remain
bool checkWin(char grid[][GRIDY]);

// takes the grid and the lenth of the ship
// once complete the grid will have a ship marked with 'a's, length long.
void addShip(int length, char grid[][GRIDY]);

int main()
{
	char grid[GRIDX][GRIDY], shotCount = SHOTS;
	bool gameOver = false;
	srand(time(0)); // new random seed
	fillGrid(grid);
	//addShip(5, grid);
	//addShip(3, grid);
	//addShip(3, grid);
	addShip(2, grid);
	paintGrid(grid);
	cout << "Welcome to Battleships! Attempt to sink the enemy fleet - a sub, 2 destroyers and a battleship!\n"
		<< "A hit gets you a bonus shot. Run out of shots and you lose the game!\n"
		<< "Enter your shot!";
	while (gameOver == false)
	{
		//hit marker, and co-ords for the shot
		int hit = 0, x = 0, y = 0;
		//bools to validate input for shot - marked true when valid shot entered
		bool xFound, yFound = false;
		//Raw input to be validated 
		string xInput = "", yInput = "";

		while (xFound == false) {
			cout << endl << "Enter the X co-ordinate: ";
			getline(cin, xInput);
			stringstream xStream(xInput);
			if (xStream >> x) {
				if ( (x > 0) && (x < 21) ) {
					xFound = true;
				} else {
					cout << endl << "Please enter a co-ordinate between 1 and 20.";
				}
			} else {
				cout << endl << "Invalid number, please try again";
			}
		}
		
		while (yFound == false) {
			cout << endl << "Enter the Y co-ordinate: ";
			getline(cin, yInput);
			stringstream yStream(yInput);
			if (yStream >> y) {
				if ( (y > 0) && (y < 21) ) {
					yFound = true;
				} else {
					cout << endl << "Please enter a co-ordinate between 1 and 20.";
				}
			} else {
				cout << endl << "Invalid number, please try again";
			}
		}

		//I can fix the mysterious shot placement by adding 1 to the shot. INVESTIGATE!
		hit = shot(x + 1, y + 1, grid);
		xFound = false;
		yFound = false;

		if (hit == 0) 
		{
			cout << endl << "A miss!" << endl;
			shotCount--;
			if (shotCount == 0)
			{
				gameOver = true;
			}
		} else {
			cout << endl << "Success! A hit!" << endl;
			win = checkWin(grid);
			if (win == true) 
			{
				gameOver = true;
			}
		}
		if (gameOver == false)
		{	
			paintGrid(grid);
			cout << "Enter your next shot!";
		}
	}
	if (win == false)
	{
	cout << "You have failed to sink the enemy fleet. The war is lost!\n"
		<< "Better luck next time!\n"
		<< "press return to exit:";
	} else {
		cout << "Winner! You showed them what for!\n"
			<< "press return to exit:";
	}
	char garbage;
	cin >> garbage;
	cout << endl;
	return 0;
}

void paintGrid(char grid[][GRIDY])
{
	for (int yi = 21; yi >= 0; yi--)
	{
		for (int xi = 0; xi < GRIDX; xi++) // iterate over both indices and print out accoring to rules
		{
			if (xi == 0) // first special case iteration - prints out the Y axis numbers (or a space or line for 0 + 1)
			{
				if (yi == 1)
				{
					cout << "__";
				}
				else if (yi == 0)
				{
					cout << "  ";
				}
				else if (yi < 11) 
				{
					cout << "0";
					cout << yi - 1;
				}
				else 
				{
					cout << yi - 1;
				}
			} else if (xi == 1) { // second special case, prints out Y axis border of grid
				cout << "| ";
			} else if (yi == 0)
			{
				if (xi < 11)
				{
					cout << "0";
					cout << xi - 1;
				}
				else 
				{
					cout << xi - 1;
				}
				// this can be changed for the letter eventually. Third special case prints out X numbers
				if (xi == 21) // ends the line at the edge of the grid
				{
					cout << endl;
				}
			}
			else if (yi == 1)
			{
				cout << "__"; // final special case - prints out X number border
				if (xi == 21) // ends the line at the edge of the grid
				{
					cout << endl;
				}
			}
			else 
			{
				if (grid[xi][yi] == 'O') // checking for miss marker (capital o)
				{
					cout << "OO";
				} 
				else if (grid[xi][yi] == 'X') // checking for hit marker (capital x)
				{
					cout << "XX";
				}
				//'cheat' mode follows to show locations of battleships. Comment out for "championship" games
				//else if (grid[xi][yi] == 'a') // checking for hit marker (capital x)
				//{
				//	cout << "aa";
				//}				
				else 
				{
					cout << "  ";
				}
				if (xi == 21) // ends the line at the edge of the grid
				{
					cout << endl;
				}
			}
		}
	}
}

int shot(int x, int y, char grid[][GRIDY])
{
	if (grid[x][y] == 'a')
	{
		grid[x][y] = 'X';
		return 1;
	}
	else
	{
		grid[x][y] = 'O';
		return 0;
	}
}

void fillGrid(char grid[][GRIDY])
{
	for (int yi = 0; yi < GRIDY; yi++)
	{
		for (int xi = 0; xi < GRIDX; xi++) // iterate over both indices and fill both arrays with empty spaces
		{
			grid[xi][yi] = ' ';
		}
	}
}

//Not working?
bool checkWin(char grid[][GRIDY])
{
	for (int yi = 0; yi < GRIDY; yi--)
	{
		for (int xi = 0; xi < GRIDX; xi++) // iterate over both indices and searches for 'a'
		{
			if (grid[xi][yi] == 'a')
			{
				return false;
			}
		}
	}
	return true;
}

void addShip(int length, char grid[][GRIDY])
{
	bool found = false, horizontal = false, clash = false;
	while (found == false)
	{
		int x, y;
		x = (rand() % 20) + 2;
		y = (rand() % 20) + 2;
		//next a random vertical / horizontal selector - 1 for horizontal
		int dir = (rand() % 2);
		if (dir == 1)
		{
			horizontal = true;
		}
		if (horizontal == true && (x + length) <= 22)
		{
			for (int i = 1; i <= length; i++)
			{
				if (grid[x][y] == 'a')
				{
					clash = true;
				}
				x++;
			}
			if (clash == false)
			{
				for (int i = 1; i <= length; i++)
				{
					grid[x][y] = 'a';
					x++;
				}
				found = true;
			}
		} else if (horizontal == false && (y + length) <= 22)
		{
			for (int i = 1; i <= length; i++)
			{
				if (grid[x][y] == 'a')
				{
					clash = true;
				}
				y++;
			}
			if (clash == false)
			{
				for (int i = 1; i <= length; i++)
				{	
					grid[x][y] = 'a';
					y++;
				}
				found = true;
			}
		}
	}
}